﻿using System;
using System.Collections.Generic;
using RGeos.SlimScene.Core;
using SlimDX;
using RGeos.Framework.OTL.OTLCalculate;
using RGeos.Framework.OTL.Interface;
using System.Drawing;
using RGeos.Geometry;
using RGeos.Basic;

namespace RGeos.Framework.OTL
{
    public class OtlDang : IDisposable, IRenderable
    {
        public string Name;

        private OtlTowerPoint mFirstTower;
        //后一塔
        public OtlTowerPoint FirstTower
        {
            get { return mFirstTower; }

        }

        private OtlTowerPoint mSecondTower;
        //前一塔
        public OtlTowerPoint SecondTower
        {
            get { return mSecondTower; }
        }

        public OTLPolyline OwnerPolyline { get; set; }
        public OtlStrainSection OwnerStrainSection { get; set; }

        //弧垂k值
        public double K;
        //水平档距
        public double Distance
        {
            get
            {
                if (mFirstTower != null && mSecondTower != null)
                {
                    Vector3 v = mSecondTower.Position - mFirstTower.Position;
                    return v.Length();
                }
                return 0;
            }
        }
        public double GetSpan()
        {
            if (mFirstTower != null && mSecondTower != null)
            {
                Vector3 v = mSecondTower.Position - mFirstTower.Position;
                return v.Length();
            }
            return 0;
        }
        public OtlDang(OtlTowerPoint last, OtlTowerPoint next, OTLPolyline owner)
        {
            mFirstTower = last;
            mSecondTower = next;
            this.OwnerPolyline = owner;
        }
        List<LineString> lineStrings = new List<LineString>();
        public void ConstructPowerline()
        {
            //构建电力线路
            if (mFirstTower != null && mSecondTower != null)
            {
                //地线
                List<IHangPoint> hangWireGroundPtsFirst = mFirstTower.GetWireGroundHangPoints();
                //导线前
                List<IHangPoint> hangWirePtsFirst = mFirstTower.GetWireFrontHangPoints();
                //跳线
                List<IHangPoint> hangJumpPtsFirst = mFirstTower.GetHangPoints((int)RgWireStyles.Jump, (int)RgIsForward.Middle);

                //地线
                List<IHangPoint> hangWireGroundPtsSecond = mFirstTower.GetWireGroundHangPoints();
                //导线后
                List<IHangPoint> hangWirePtsSecond = mFirstTower.GetWireFrontHangPoints();
                //跳线
                List<IHangPoint> hangJumpPtsSecond = mFirstTower.GetHangPoints((int)RgWireStyles.Jump, (int)RgIsForward.Middle);

                double span = this.GetSpan();
                Vector3 directionFirst = mFirstTower.GetForwardDirection();
                Vector3 directionSecond = mSecondTower.GetForwardDirection();
                double dirAngleFirst = RgMath.GetQuadrantAngle(directionFirst.X, directionFirst.Y);
                double dirAngleSecond = RgMath.GetQuadrantAngle(directionSecond.X, directionSecond.Y);
                if (span < OtlContext.Resample)
                {
                    throw new ArgumentException("档间距过小");
                }
                int sampleNum = (int)(span / OtlContext.Resample);
                if (sampleNum == 0)
                {
                    throw new ArgumentException("档间距过小");
                }
                //构建档间地线
                if (hangWireGroundPtsFirst.Count == hangWireGroundPtsSecond.Count)
                {
                    int n = hangWireGroundPtsFirst.Count;
                    for (int i = 0; i < n; i++)
                    {
                        Point3d[] pts = new Point3d[sampleNum + 1];
                        LineString line = new LineString();
                        IHangPoint left = hangWireGroundPtsFirst[i];
                        IHangPoint right = hangWireGroundPtsSecond[i];

                        double radis0 = Math.Sqrt(left.Coordinate.X * left.Coordinate.X + left.Coordinate.Y * left.Coordinate.Y);
                        double angle0 = Math.Atan2(left.Coordinate.X, left.Coordinate.Y);
                        double angle00 = (dirAngleFirst + angle0) > Math.PI * 2 ? (dirAngleFirst + angle0) - Math.PI * 2 : (dirAngleFirst + angle0);

                        double radis1 = Math.Sqrt(right.Coordinate.X * right.Coordinate.X + right.Coordinate.Y * right.Coordinate.Y);
                        double angle1 = Math.Atan2(right.Coordinate.X, right.Coordinate.Y);
                        double angle10 = (dirAngleSecond + angle1) > Math.PI * 2 ? (dirAngleSecond + angle1) - Math.PI * 2 : (dirAngleSecond + angle1);

                        Point3d pt1 = new Point3d();
                        pt1.X = mFirstTower.Position.X + radis0 * Math.Cos(angle00);
                        pt1.Y = mFirstTower.Position.Y + radis0 * Math.Sin(angle00);
                        pt1.Z = left.Coordinate.Z;
                        Point3d pt2 = new Point3d();
                        pt2.X = mSecondTower.Position.X + radis1 * Math.Cos(angle10);
                        pt2.Y = mSecondTower.Position.Y + radis1 * Math.Sin(angle10);
                        pt2.Z = right.Coordinate.Z;

                        Point3d vect = pt2 - pt1;
                        // double k = CalculatePolylineK(this.OwnerStrainSection.HangWireTypeSets[i].EWireStyle, Context.Instance().CurrentCondition);
                        WireStyle wireStyle = this.OwnerStrainSection.HangWireTypeSets[i].EWireStyle;
                        if (wireStyle != null && OtlContext.Instance().CurrentCondition != null && OwnerStrainSection != null)
                        {
                            double drepresent = OwnerStrainSection.GetRepresentDistance();
                            ConductorStressMath cal = new ConductorStressMath(OtlContext.Instance().ConditionList, wireStyle, 2.5, 20, drepresent);
                            cal.CalculatePolylineK();
                            double a0Area = cal.GetPolylineZL(OtlContext.Instance().CurrentCondition.ConditionName);
                            double rArea = cal.GetPolylineZHZH(OtlContext.Instance().CurrentCondition.ConditionName);

                            double a0_Wire, r_Wire;
                            a0_Wire = a0Area / wireStyle.Area;
                            r_Wire = rArea / wireStyle.Area;
                            for (int isample = 0; isample < sampleNum; isample++)
                            {
                                Point3d tmp = new Point3d();
                                vect.Z = 0;
                                tmp = pt1 + vect.normalize() * OtlContext.Resample * isample;
                                double z = GetZ(a0_Wire, r_Wire, tmp, pt1, pt2);
                                tmp.Z = z;
                                pts[isample] = tmp;
                            }
                            pts[sampleNum] = new Point3d(pt2.X, pt2.Y, pt2.Z);
                            line.Coordinates = pts;
                            lineStrings.Add(line);
                        }
                    }
                }
                else
                {
                    throw new ArgumentException(string.Format("{0}档地线挂点数目不一致！", this.Name));
                }
                //构建档间导线
                if (hangWirePtsFirst.Count == hangWirePtsSecond.Count)
                {
                    int n = hangWirePtsFirst.Count;
                    for (int i = 0; i < n; i++)
                    {
                        Point3d[] pts = new Point3d[sampleNum + 1];
                        LineString line = new LineString();
                        IHangPoint left = hangWirePtsFirst[i];
                        IHangPoint right = hangWirePtsSecond[i];

                        double radis0 = Math.Sqrt(left.Coordinate.X * left.Coordinate.X + left.Coordinate.Y * left.Coordinate.Y);
                        double angle0 = Math.Atan2(left.Coordinate.X, left.Coordinate.Y);
                        double angle00 = (dirAngleFirst + angle0) > Math.PI * 2 ? (dirAngleFirst + angle0) - Math.PI * 2 : (dirAngleFirst + angle0);

                        double radis1 = Math.Sqrt(right.Coordinate.X * right.Coordinate.X + right.Coordinate.Y * right.Coordinate.Y);
                        double angle1 = Math.Atan2(right.Coordinate.X, right.Coordinate.Y);
                        double angle10 = (dirAngleSecond + angle1) > Math.PI * 2 ? (dirAngleSecond + angle1) - Math.PI * 2 : (dirAngleSecond + angle1);

                        Point3d pt1 = new Point3d();
                        pt1.X = mFirstTower.Position.X + radis0 * Math.Cos(angle00);
                        pt1.Y = mFirstTower.Position.Y + radis0 * Math.Sin(angle00);
                        pt1.Z = left.Coordinate.Z;
                        Point3d pt2 = new Point3d();
                        pt2.X = mSecondTower.Position.X + radis1 * Math.Cos(angle10);
                        pt2.Y = mSecondTower.Position.Y + radis1 * Math.Sin(angle10);
                        pt2.Z = right.Coordinate.Z;

                        Point3d vect = pt2 - pt1;
                        // double k = CalculatePolylineK(this.OwnerStrainSection.HangWireTypeSets[i].EWireStyle, Context.Instance().CurrentCondition);
                        WireStyle wireStyle = this.OwnerStrainSection.HangWireTypeSets[i].EWireStyle;
                        if (wireStyle != null && OtlContext.Instance().CurrentCondition != null && OwnerStrainSection != null)
                        {
                            double drepresent = OwnerStrainSection.GetRepresentDistance();
                            ConductorStressMath cal = new ConductorStressMath(OtlContext.Instance().ConditionList, wireStyle, 2.5, 20, drepresent);
                            cal.CalculatePolylineK();
                            double a0Area = cal.GetPolylineZL(OtlContext.Instance().CurrentCondition.ConditionName);
                            double rArea = cal.GetPolylineZHZH(OtlContext.Instance().CurrentCondition.ConditionName);

                            double a0_Wire, r_Wire;
                            a0_Wire = a0Area / wireStyle.Area;
                            r_Wire = rArea / wireStyle.Area;
                            for (int isample = 0; isample < sampleNum; isample++)
                            {
                                Point3d tmp = new Point3d();
                                vect.Z = 0;
                                tmp = pt1 + vect.normalize() * OtlContext.Resample * isample;
                                double z = GetZ(a0_Wire, r_Wire, tmp, pt1, pt2);
                                tmp.Z = z;
                                pts[isample] = tmp;
                            }
                            pts[sampleNum] = new Point3d(pt2.X, pt2.Y, pt2.Z);
                            line.Coordinates = pts;
                            lineStrings.Add(line);
                        }
                    }
                }
                else
                {
                    throw new ArgumentException(string.Format("{0}档导线挂点数目不一致！", this.Name));
                }
            }
        }
        /* 参数值得来源
         * double a0, r;
         * a0 = HuchuiCal.Conditions[0].ZL_Wire / HuchuiCal.EvWireType.Area;
         * r = HuchuiCal.Conditions[0].ZHZH_Wire / HuchuiCal.EvWireType.Area;
         */
        /// <summary>
        /// 计算悬链线任意一点弧垂
        /// </summary>
        /// <param name="a0">导线最低点水平应力</param>
        /// <param name="r">传入电线比载N/m</param>
        /// <param name="pt1">悬链线任意中间节点</param>
        /// <param name="ptHang1">左挂点</param>
        /// <param name="ptHang2">右挂点</param>
        /// <returns></returns>
        public double HuChui(double a0, double r, Point3d pt1, Point3d ptHang1, Point3d ptHang2)
        {
            OTLCatenaryline catenary = new OTLCatenaryline();
            catenary.Alpha0 = a0;
            catenary.Gamma = r;
            catenary.H = ptHang2.Z - ptHang1.Z;
            catenary.L = SpatialMeasure.Distance2D(ptHang1, ptHang2);
            double fx = catenary.Compute_fx(SpatialMeasure.Distance2D(ptHang1, pt1));
            return fx;
        }
        /// <summary>
        /// 计算悬链线任意一点的高程Z值
        /// </summary>
        /// <param name="a0">导线最低点水平应力</param>
        /// <param name="r">传入电线比载N/m</param>
        /// <param name="pt1">悬链线任意中间节点</param>
        /// <param name="ptHang1">左挂点</param>
        /// <param name="ptHang2">右挂点</param>
        /// <returns></returns>
        public double GetZ(double a0, double r, Point3d pt1, Point3d ptHang1, Point3d ptHang2)
        {
            double out_HuChui = HuChui(a0, r, pt1, ptHang1, ptHang2);
            double disTemp = SpatialMeasure.Distance2D(ptHang1, ptHang2);
            double disPtHang1ToIntersect = SpatialMeasure.Distance2D(pt1, ptHang2);
            double out_Z = ptHang1.Z + (ptHang2.Z - ptHang1.Z) / disTemp * disPtHang1ToIntersect - out_HuChui;
            return out_Z;
        }


        public double CalculatePolylineK(WireStyle wireStyle, Condition condition)
        {
            if (wireStyle != null && condition != null && OwnerStrainSection != null)
            {
                ConductorStressMath cal = new ConductorStressMath(OtlContext.Instance().ConditionList, wireStyle, 2.5, 20, OwnerStrainSection.Represent);
                cal.CalculatePolylineK();
                double k1 = cal.GetPolylineK(condition.ConditionName);
                return k1;
            }
            return 0;
        }


        public bool IsOn = true;
        public bool IsInitialize = false;
        public BoundingBox BoundingBox;
        private List<RenderableLineString> listRenders = null;
        //准备好对象
        public void Initialize(DrawArgs drawArgs)
        {
            ConstructPowerline();
            if (listRenders == null)
            {
                listRenders = new List<RenderableLineString>();
            }
            for (int i = 0; i < lineStrings.Count; i++)
            {
                RenderableLineString render = new RenderableLineString("Hello", drawArgs.CurrentWorld, lineStrings[i].Coordinates, Color.Red);
                render.IsOn = true;
                render.RenderPriority = RenderPriority.Custom;
                listRenders.Add(render);
            }
            IsInitialize = true;
        }
        //准备好渲染对象
        public void Update(DrawArgs drawArgs)
        {
            if (IsOn && !IsInitialize)
            {
                Initialize(drawArgs);
            }
            if (listRenders == null)
            {
                return;
            }
            for (int i = 0; i < listRenders.Count; i++)
            {
                listRenders[i].Initialize(drawArgs);
            }
        }

        public void Render(DrawArgs drawArgs)
        {
            if (IsOn && IsInitialize)
            {
                for (int i = 0; i < listRenders.Count; i++)
                {
                    if (listRenders[i].Initialized)
                    {
                        listRenders[i].Render(drawArgs);
                    }

                }
            }
        }

        public void Dispose()
        {
            if (listRenders != null)
            {
                listRenders.Clear();
            }
            if (lineStrings != null)
            {
                lineStrings.Clear();
            }
            IsInitialize = false;
        }
    }
}
